/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package merlion.mrp.ppm.session;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import merlion.common.util.Consts;
import merlion.crm.sopm.entity.ItemLine;
import merlion.crm.sopm.entity.SalesOrder;
import merlion.mrp.ppm.entity.ArchivedIndivSOP;
import merlion.mrp.ppm.entity.IndivSOP;
import merlion.mrp.ppm.entity.SOP;
import merlion.mrp.ppm.entity.SalesForecast;
import merlion.mrp.ppm.pojo.LabelNValue;
import merlion.scm.lcm.entity.DeliveryOrder;

/**
 *
 * @author Zhang Ying
 */
@Stateless
public class SalesForecastingSession implements SalesForecastingSessionLocal, SalesForecastingSessionRemote {

    @PersistenceContext
    private EntityManager entityManager;
    @EJB
    private SalesOptPlanningSessionLocal sopSession;

    @Override
    public boolean checkPendingForecasts(int year, int month) {
        // assume it is accumulative, just need to check the previous one
        int mm = month;
        if (month == 1) {
            month = 7;
            year -= 1;
        } else {
            month = 1;
        }
        Integer y = new Integer(year);
        Integer m = new Integer(month);
        try {
            Calendar calendar = Calendar.getInstance();
            Date date = calendar.getTime();
            SimpleDateFormat sdf = new SimpleDateFormat("MM");
            int currentMonth = Integer.valueOf(sdf.format(date));
            sdf = new SimpleDateFormat("yyyy");
            int currentYear = Integer.valueOf(sdf.format(date));
            boolean monthCorrect = false;
            if (currentMonth > 6 && mm < 7 && currentYear == year) {
                monthCorrect = true;
            } else if (currentMonth < 7 && mm > 6 && currentYear == (year + 1)) {
                monthCorrect = true;
            }
            Query tempQ = entityManager.createQuery("SELECT sf FROM SalesForecast sf");
            if (tempQ.getResultList().isEmpty() && monthCorrect) {
                return false;
            }
            Query query = entityManager.createQuery("SELECT sf FROM SalesForecast sf WHERE sf.startPeriodYear=:p1 AND sf.startPeriodMonth=:p2");
            query.setParameter("p1", y);
            query.setParameter("p2", m);
            return query.getResultList().isEmpty();
        } catch (Exception ex) {
            return true;
        }
    }

    @Override
    public boolean checkExistedForecasts(int year, int month) {
        Integer y = new Integer(year);
        Integer m = new Integer(month);
        try {
            Query query = entityManager.createQuery("SELECT sf FROM SalesForecast sf WHERE sf.startPeriodYear=:p1 AND sf.startPeriodMonth=:p2");
            query.setParameter("p1", y);
            query.setParameter("p2", m);
            return !query.getResultList().isEmpty();
        } catch (Exception ex) {
            return true;
        }
    }

    @Override
    public ArrayList<ArrayList<Long>> getPreviousTotalSales(Long selectedYear, boolean firstHalf) {
        System.out.println("selectedYear is :" + selectedYear);
        int previousYear = selectedYear.intValue() - 1;
        // init result
        ArrayList<ArrayList<Long>> result = new ArrayList<ArrayList<Long>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> halfYearPerProd = new ArrayList<Long>();
            for (int j = 0; j < 6; j++) {
                Long temp = new Long(0);
                halfYearPerProd.add(temp);
            }
            result.add(halfYearPerProd);
        }
        // retrieve data
        Query query = entityManager.createQuery("SELECT so FROM SalesOrder so WHERE so.salesOrderStatus=:p1");
        query.setParameter("p1", Consts.ORDER_SHIPPED);
        List<SalesOrder> sos = (List<SalesOrder>) query.getResultList();
        for (SalesOrder so : sos) {
            Timestamp createdDate = so.getSalesOrderDate();
            SimpleDateFormat sdf = new SimpleDateFormat("MM");
            int month = Integer.valueOf(sdf.format(createdDate));
            sdf = new SimpleDateFormat("yyyy");
            int year = Integer.valueOf(sdf.format(createdDate));
            // need to retreve the correct month's data
            boolean monthCorrect = false;
            if (month <= 6 && firstHalf) {
                monthCorrect = true;
            } else if (month > 6 && !firstHalf) {
                monthCorrect = true;
            } else {
                monthCorrect = false;
            }

            if (year == previousYear && monthCorrect) {
                Collection<DeliveryOrder> ols = so.getDeliveryOrders();
                for (DeliveryOrder ol : ols) {
                    Collection<ItemLine> ils = ol.getItemLines();
                    for (ItemLine il : ils) {
                        String productTypeStr = il.getProduct().getProductType();
                        ArrayList<Long> halfYearPerProd;
                        if (productTypeStr.equals(Consts.ProductType.BAR_A.getText())) {
                            halfYearPerProd = result.get(0);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_B.getText())) {
                            halfYearPerProd = result.get(1);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_C.getText())) {
                            halfYearPerProd = result.get(2);
                        } else {
                            halfYearPerProd = result.get(3);
                        }
                        if (firstHalf) {
                            // if it is from Jan-Jun: -1
                            halfYearPerProd.set(month - 1, il.getQtyOrderedCase() + halfYearPerProd.get(month - 1));
                        } else {
                            // if it is from Jul-Dec: -7
                            halfYearPerProd.set(month - 7, il.getQtyOrderedCase() + halfYearPerProd.get(month - 7));
                        }
                    }
                }
            }
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Long>> getPreviousPromotion(Long selectedYear, boolean firstHalf) {
        int previousYear = selectedYear.intValue() - 1;
        ArrayList<ArrayList<Long>> result = new ArrayList<ArrayList<Long>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> halfYearPerProd = new ArrayList<Long>();
            for (int j = 0; j < 6; j++) {
                Long temp = new Long(0);
                halfYearPerProd.add(temp);
            }
            result.add(halfYearPerProd);
        }
        // retrieve data
        Query query = entityManager.createQuery("SELECT so FROM SalesOrder so WHERE so.salesOrderStatus=:p1");
        query.setParameter("p1", Consts.ORDER_SHIPPED);
        List<SalesOrder> sos = (List<SalesOrder>) query.getResultList();
        for (SalesOrder so : sos) {
            Timestamp createdDate = so.getSalesOrderDate();
            SimpleDateFormat sdf = new SimpleDateFormat("MM");
            int month = Integer.valueOf(sdf.format(createdDate));
            sdf = new SimpleDateFormat("yyyy");
            int year = Integer.valueOf(sdf.format(createdDate));
            // need to retreve the correct month's data
            boolean monthCorrect = false;
            if (month <= 6 && firstHalf) {
                monthCorrect = true;
            } else if (month > 6 && !firstHalf) {
                monthCorrect = true;
            } else {
                monthCorrect = false;
            }
            // if it is promotion sales, then added in
            if (year == previousYear && monthCorrect && so.getPromotion().equals(Boolean.TRUE)) {
                Collection<DeliveryOrder> ols = so.getDeliveryOrders();
                for (DeliveryOrder ol : ols) {
                    Collection<ItemLine> ils = ol.getItemLines();
                    for (ItemLine il : ils) {
                        String productTypeStr = il.getProduct().getProductType();
                        ArrayList<Long> halfYearPerProd;
                        if (productTypeStr.equals(Consts.ProductType.BAR_A.getText())) {
                            halfYearPerProd = result.get(0);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_B.getText())) {
                            halfYearPerProd = result.get(1);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_C.getText())) {
                            halfYearPerProd = result.get(2);
                        } else {
                            halfYearPerProd = result.get(3);
                        }
                        if (firstHalf) {
                            // if it is from Jan-Jun: -1
                            halfYearPerProd.set(month - 1, il.getQtyOrderedCase() + halfYearPerProd.get(month - 1));
                        } else {
                            // if it is from Jul-Dec: -7
                            halfYearPerProd.set(month - 7, il.getQtyOrderedCase() + halfYearPerProd.get(month - 7));
                        }
                    }
                }
            }
        }
        return result;
    }

    @Override
    public ArrayList<Long> getPreviousIndustryTotalDemand(Long selectedYear, boolean firstHalf) {
        ArrayList<Long> result = new ArrayList<Long>();
        String fileName = Consts.FORECAST_INDUSTRY_CSV_PATH;
        try {
            //storeValues.clear();//just in case this is the second call of the ReadFile Method./
            BufferedReader br = new BufferedReader(new FileReader(fileName));

            StringTokenizer st = null;

            while ((fileName = br.readLine()) != null) {
                System.out.println(fileName);
                //break comma separated line using ","
                st = new StringTokenizer(fileName, ",");
                // year and month
                int year = -1;
                int month = -1;
                int counter = 0;
                while (st.hasMoreTokens()) {
                    String token = st.nextToken();
                    if (counter == 0) {
                        year = Integer.valueOf(token);
                    } else if (counter == 1) {
                        month = Integer.valueOf(token);
                    } else {
                        // need to retreve the correct month's data
                        boolean monthCorrect = false;
                        if (month <= 6 && firstHalf) {
                            monthCorrect = true;
                        } else if (month > 6 && !firstHalf) {
                            monthCorrect = true;
                        } else {
                            monthCorrect = false;
                        }
                        if (year == (selectedYear.intValue() - 1) && monthCorrect) {
                            result.add(Long.valueOf(token));
                            System.out.println("add token");
                        }
                    }
                    counter++;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        int currentSize = result.size();
        for (int i = 0; i < (6 - currentSize); i++) {
            result.add(Long.valueOf("0"));
        }
        return result;
    }

    @Override
    public ArrayList<Integer> getStaticPeriods(Long selectedYear, boolean firstHalf) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        int numOfM;
        if (firstHalf) {
            numOfM = (selectedYear.intValue() - Consts.BASE_YEAR) * 12 + 1;
        } else {
            numOfM = (selectedYear.intValue() - Consts.BASE_YEAR) * 12 + 7;
        }
        for (int i = 0; i < 6; i++) {
            result.add(new Integer(numOfM + i));
        }
        return result;
    }

    @Override
    public ArrayList<Integer> getAllStaticPeriods(int currentYear, int currentMonth) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        // to the month before current month
        int numOfM = (currentYear - Consts.BASE_YEAR) * 12 + currentMonth - 1;
        for (int i = 0; i < numOfM; i++) {
            result.add(new Integer(i + 1));
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Long>> getAllProductsActualDemands(int currentYear, int currentMonth) {
        // get all the actual demands except current month (pay attention to month 1)
        // init result
        ArrayList<ArrayList<Long>> result = new ArrayList<ArrayList<Long>>();
        int size = (currentYear - Consts.BASE_YEAR) * 12 + currentMonth - 1;
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> halfYearPerProd = new ArrayList<Long>();
            for (int j = 0; j < size; j++) {
                Long temp = new Long(0);
                halfYearPerProd.add(temp);
            }
            result.add(halfYearPerProd);
        }
        // retrieve data
        Query query = entityManager.createQuery("SELECT so FROM SalesOrder so WHERE so.salesOrderStatus=:p1");
        query.setParameter("p1", Consts.ORDER_SHIPPED);
        List<SalesOrder> sos = (List<SalesOrder>) query.getResultList();
        for (SalesOrder so : sos) {
            Timestamp createdDate = so.getSalesOrderDate();
            SimpleDateFormat sdf = new SimpleDateFormat("MM");
            int month = Integer.valueOf(sdf.format(createdDate));
            sdf = new SimpleDateFormat("yyyy");
            int year = Integer.valueOf(sdf.format(createdDate));
            // need to retreve the correct month's data
            boolean monthCorrect = false;
            if (currentMonth == 1 && year <= (currentYear - 1)) {
                monthCorrect = true;
            } else if (month < currentMonth && year == currentYear) {
                monthCorrect = true;
            } else if (year < currentYear) {
                monthCorrect = true;
            } else {
                monthCorrect = false;
            }

            if (monthCorrect) {
                Collection<DeliveryOrder> ols = so.getDeliveryOrders();
                for (DeliveryOrder ol : ols) {
                    Collection<ItemLine> ils = ol.getItemLines();
                    for (ItemLine il : ils) {
                        String productTypeStr = il.getProduct().getProductType();
                        ArrayList<Long> wholePeriod;
                        if (productTypeStr.equals(Consts.ProductType.BAR_A.getText())) {
                            wholePeriod = result.get(0);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_B.getText())) {
                            wholePeriod = result.get(1);
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_C.getText())) {
                            wholePeriod = result.get(2);
                        } else {
                            wholePeriod = result.get(3);
                        }
                        int index = (year - Consts.BASE_YEAR) * 12 + month - 1;
                        wholePeriod.set(index, il.getQtyOrderedCase() + wholePeriod.get(index));
                    }
                }
            }
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Long>> getAllProductDesDemand(ArrayList<Integer> allStaticPeriods, ArrayList<Double> trend, ArrayList<Double> level) {
        ArrayList<ArrayList<Long>> result = new ArrayList<ArrayList<Long>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> productXDD = new ArrayList<Long>();
            double l = 1.0 * level.get(i);
            double t = 1.0 * trend.get(i);
            for (int j = 0; j < allStaticPeriods.size(); j++) {
                Long item = new Long(Math.round(l + t * allStaticPeriods.get(j)));
                productXDD.add(item);
            }
            result.add(productXDD);
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Double>> getAllProductDesFactor(ArrayList<ArrayList<Long>> allDesDemand, ArrayList<ArrayList<Long>> allActualDemands) {
        ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>();
        int size = allActualDemands.get(0).size();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> productDD = allDesDemand.get(i);
            ArrayList<Long> productAD = allActualDemands.get(i);
            ArrayList<Double> partialResult = new ArrayList<Double>();
            for (int j = 0; j < size; j++) {
                Double d = 1.0 * productAD.get(j) / productDD.get(j);
                partialResult.add(d);
            }
            result.add(partialResult);
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Double>> getLinearRegressResultLnT(ArrayList<ArrayList<Long>> allDesDemandFromActual, ArrayList<Integer> allStaticPeriods) {
        ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> productX = allDesDemandFromActual.get(i);
            // compute the sum
            double sumx = 0.0;
            double sumy = 0.0;
            int counter = 0;
            for (int j = 0; j < allStaticPeriods.size(); j++) {
                if (productX.get(j) > -1) {
                    sumy = sumy + productX.get(j);
                    sumx = sumx + allStaticPeriods.get(j);
                    counter++;
                    System.out.println("counter : " + counter + "product x : " + productX.get(j) + "sumx: " + sumx + "sumy: " + sumy + " j:" + j + "period :" + allStaticPeriods.get(j));
                }
            }
            double xbar = sumx / counter;
            double ybar = sumy / counter;
            // compute level and trend
            double xxbar = 0.0;
            double xybar = 0.0;
            for (int j = 0; j < allStaticPeriods.size(); j++) {
                long y = productX.get(j);
                if (y > -1) {
                    long x = allStaticPeriods.get(j);
                    xxbar = xxbar + Math.pow((x - xbar), 2);
                    xybar = xybar + (x - xbar) * (y - ybar);
                    System.out.println("xxbar :" + xxbar + " xybar: " + xybar);
                }
            }
            double t = xybar / xxbar;
            double l = ybar - t * xbar;
            ArrayList<Double> partialResult = new ArrayList<Double>();
            partialResult.add(l);
            partialResult.add(t);
            result.add(partialResult);
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Double>> getAllProductEstimDesFactor(ArrayList<ArrayList<Double>> allDesFactor, ArrayList<Integer> pdicities) {
        ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>();
        for (int i = 0; i < 4; i++) {
            int pd = pdicities.get(i);
            ArrayList<Double> productXDF = allDesFactor.get(i);
            int size = productXDF.size();
            ArrayList<Double> productXSumOfDF = new ArrayList<Double>();
            ArrayList<Integer> productXCount = new ArrayList<Integer>();
            ArrayList<Double> partialResult = new ArrayList<Double>();
            for (int j = 0; j < pd; j++) {
                productXSumOfDF.add(0.0);
                productXCount.add(0);
            }
            for (int j = 0; j < size; j++) {
                int pos = j % pd;
                productXSumOfDF.set(pos, productXSumOfDF.get(pos) + productXDF.get(j));
                productXCount.set(pos, productXCount.get(pos) + 1);
            }
            for (int j = 0; j < productXCount.size(); j++) {
                try {
                    partialResult.add(productXSumOfDF.get(j) / productXCount.get(j));
                } catch (ArithmeticException ex) {
                    partialResult.add(0.0);
                }
            }
            result.add(partialResult);
        }
        return result;
    }

    @Override
    public ArrayList<ArrayList<Long>> getAllProductDesDemandFromActual(ArrayList<ArrayList<Long>> allActualDemands, ArrayList<Integer> pdicities) {
        ArrayList<ArrayList<Long>> result = new ArrayList<ArrayList<Long>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<Long> productXAD = allActualDemands.get(i);
            int proXPeriodiocity = pdicities.get(i);
            int size = productXAD.size();
            ArrayList<Long> partialResult = new ArrayList<Long>();
            // init result array
            for (int j = 0; j < size; j++) {
                partialResult.add(new Long(0));
            }
            if (proXPeriodiocity % 2 == 0) {
                // p is even
                for (int j = 0; j < size; j++) {
                    int monthIndex = j + 1;
                    if ((monthIndex - proXPeriodiocity / 2 > 0) && (monthIndex + proXPeriodiocity / 2 <= size)) {
                        Long sum = new Long(0);
                        for (int k = (monthIndex - proXPeriodiocity / 2 + 1); k <= (monthIndex + proXPeriodiocity / 2 - 1); k++) {
                            sum += productXAD.get(k - 1);
                        }
                        Long r = Math.round(1.0 * sum / proXPeriodiocity + 1.0 * (productXAD.get(j - proXPeriodiocity / 2) + productXAD.get(j + proXPeriodiocity / 2)) / (2 * proXPeriodiocity));
                        partialResult.set(j, r);
                    } else {
                        partialResult.set(j, new Long(-1));
                    }
                }
            } else {
                // p is odd
                for (int j = 0; j < size; j++) {
                    int monthIndex = j + 1;
                    if ((monthIndex - proXPeriodiocity / 2 > 0) && (monthIndex + proXPeriodiocity / 2 <= size)) {
                        Long sum = new Long(0);
                        for (int k = (monthIndex - proXPeriodiocity / 2); k <= (monthIndex + proXPeriodiocity / 2); k++) {
                            sum += productXAD.get(k - 1);
                        }
                        Long r = Math.round(1.0 * sum / proXPeriodiocity);
                        partialResult.set(j, r);
                    } else {
                        partialResult.set(j, new Long(-1));
                    }
                }
            }
            result.add(partialResult);
        }
        return result;
    }

    @Override
    public boolean persistSalesForecast(SalesForecast newSalesForecast, Long staffId) {
        try {
//            Staff s = entityManager.find(Staff.class, staffId);
//            newSalesForecast.setStaff(s);
//            s.getSalesForecasts().add(newSalesForecast);
//            entityManager.merge(s);
            entityManager.merge(newSalesForecast);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public Collection<SalesForecast> getAllSalesForecast() {
        Query query = entityManager.createQuery("SELECT sf FROM SalesForecast sf");
        return query.getResultList();
    }

    @Override
    public SalesForecast getSalesForecastFromIdStr(String selectedSFId) {
        Query query = entityManager.createQuery("SELECT sf FROM SalesForecast sf WHERE sf.sfIdStr=:p1");
        query.setParameter("p1", selectedSFId);
        return (SalesForecast) query.getSingleResult();
    }

    @Override
    public boolean checkValidForecastId(String selectedSFId) {
        Query query = entityManager.createQuery("SELECT sf FROM SalesForecast sf WHERE sf.sfIdStr=:p1");
        query.setParameter("p1", selectedSFId);
        return !query.getResultList().isEmpty();
    }

    @Override
    public boolean saveEditedSalesForecast(SalesForecast selectedSF) {
        try {
            entityManager.merge(selectedSF);
            //TODO: update related sops

            // update sales forecast figures
            for (SOP sop : selectedSF.getSops()) {

                //create Archive
                int archivedTimes;
                if (sop.returnProductIndivSOP(0).getArchivedIndivSops() == null || sop.returnProductIndivSOP(0).getArchivedIndivSops().isEmpty()) {
                    archivedTimes = 0;
                } else {
                    archivedTimes = sop.returnProductIndivSOP(0).getArchivedIndivSops().size();
                }
                for (int i = 0; i < 4; i++) {
                    IndivSOP indivSOP = sop.returnProductIndivSOP(i);
                    ArchivedIndivSOP archivedIndiv = new ArchivedIndivSOP(archivedTimes, indivSOP.getSalesforcastValues(), indivSOP.getUnplannedDemandList(), indivSOP.getProductionPlanList(), indivSOP.getInventoryList());
                    indivSOP.getArchivedIndivSops().add(archivedIndiv);
                }

                // get sales forecast figure for sop
                if (sop.getStartPeriodMonth() == 1 || sop.getStartPeriodMonth() == 7) {
                    // 1, 7
                    for (int i = 0; i < 4; i++) {
                        int times = selectedSF.returnProductIndivForecast(i).returnNumberOfUpdates();
                        for (int j = 0; j < 3; j++) {
                            sop.returnProductIndivSOP(i).getSalesforcastValues().get(j).setLongValue(selectedSF.returnProductIndivForecast(i).returnUpdateIndivs(times - 1).getFinalValues().get(j).getLongValue());
                        }
                    }
                } else {
                    // 4, 10
                    for (int i = 0; i < 4; i++) {
                        int times = selectedSF.returnProductIndivForecast(i).returnNumberOfUpdates();
                        for (int j = 3; j < 6; j++) {
                            sop.returnProductIndivSOP(i).getSalesforcastValues().get(j - 3).setLongValue(selectedSF.returnProductIndivForecast(i).returnUpdateIndivs(times - 1).getFinalValues().get(j).getLongValue());
                        }
                    }
                }

                ArrayList<Long> previousInventories = sopSession.getInventoryOfPrevSeasonLastMonth(sop.getStartPeriodYear(), sop.getStartPeriodMonth());

                //re -calculate the sop
                for (int i = 0; i < 4; i++) {
                    for (int j = 0; j < 3; j++) {
                        Long sfVal = sop.returnProductIndivSOP(i).getSalesforcastValues().get(j).getLongValue();
                        Long unplanned = sop.returnProductIndivSOP(i).getUnplannedDemandList().get(j).getLongValue();
                        Long totalDemand = sfVal + unplanned;
                        Long inv = sop.returnProductIndivSOP(i).getInventoryList().get(j).getLongValue();
                        Long prevInventory;
                        if (j == 0) {
                            prevInventory = previousInventories.get(i);
                        } else {
                            prevInventory = sop.returnProductIndivSOP(i).getInventoryList().get(j - 1).getLongValue();
                        }
                        sop.returnProductIndivSOP(i).getUnplannedDemandList().get(j).setLongValue(unplanned);
                        sop.returnProductIndivSOP(i).getInventoryList().get(j).setLongValue(inv);
                        sop.returnProductIndivSOP(i).getProductionPlanList().get(j).setLongValue(totalDemand + inv - prevInventory);
                    }
                }

                // merge sop

                sopSession.persistMrpSop(sop);
            }

            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public ArrayList<LabelNValue> getMovAverage(Integer selectedProductId, Timestamp currentTime, Integer movingAvgIndexN) {
        if (movingAvgIndexN <= 0) {
            return null;
        }

        // need to check whether has so many years of data
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy");
        int currentYear = Integer.valueOf(sdf1.format(currentTime));
        SimpleDateFormat sdf2 = new SimpleDateFormat("MM");
        int currentMonth = Integer.valueOf(sdf2.format(currentTime));
        int numOfM = (currentYear - Consts.BASE_YEAR) * 12 + currentMonth - 1;
        if (movingAvgIndexN > numOfM) {
            return null;
        }
        // create result
        ArrayList<LabelNValue> result = new ArrayList<LabelNValue>();

        // get all the values for computing moving average
        ArrayList<Long> actualDemandsForOneProduct = new ArrayList<Long>();
        for (int i = 0; i < numOfM; i++) {
            actualDemandsForOneProduct.add(new Long(0));
        }
        Query query = entityManager.createQuery("SELECT so FROM SalesOrder so WHERE so.salesOrderStatus=:p1");
        query.setParameter("p1", Consts.ORDER_SHIPPED);
        List<SalesOrder> sos = (List<SalesOrder>) query.getResultList();
        for (SalesOrder so : sos) {
            Timestamp createdDate = so.getSalesOrderDate();
            SimpleDateFormat sdf = new SimpleDateFormat("MM");
            int month = Integer.valueOf(sdf.format(createdDate));
            sdf = new SimpleDateFormat("yyyy");
            int year = Integer.valueOf(sdf.format(createdDate));
            // need to retreve the correct month's data
            boolean monthCorrect = false;
            if (currentMonth == 1 && year <= (currentYear - 1)) {
                monthCorrect = true;
            } else if (month < currentMonth && year == currentYear) {
                monthCorrect = true;
            } else if (year < currentYear) {
                monthCorrect = true;
            } else {
                monthCorrect = false;
            }

            if (monthCorrect) {
                Collection<DeliveryOrder> ols = so.getDeliveryOrders();
                for (DeliveryOrder ol : ols) {
                    Collection<ItemLine> ils = ol.getItemLines();
                    for (ItemLine il : ils) {
                        String productTypeStr = il.getProduct().getProductType();
                        int index = (year - Consts.BASE_YEAR) * 12 + month - 1;
                        if (productTypeStr.equals(Consts.ProductType.BAR_A.getText()) && selectedProductId.equals(0)) {
                            actualDemandsForOneProduct.set(index, il.getQtyOrderedCase() + actualDemandsForOneProduct.get(index));
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_B.getText()) && selectedProductId.equals(1)) {
                            actualDemandsForOneProduct.set(index, il.getQtyOrderedCase() + actualDemandsForOneProduct.get(index));
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_C.getText()) && selectedProductId.equals(2)) {
                            actualDemandsForOneProduct.set(index, il.getQtyOrderedCase() + actualDemandsForOneProduct.get(index));
                        } else if (productTypeStr.equals(Consts.ProductType.BAR_D.getText()) && selectedProductId.equals(3)) {
                            actualDemandsForOneProduct.set(index, il.getQtyOrderedCase() + actualDemandsForOneProduct.get(index));
                        }
                    }
                }
            }
        }

        if (actualDemandsForOneProduct != null) {
            for (int i = 0; i < movingAvgIndexN; i++) {
                int indexOfM = numOfM - i - 1;
                Long value = actualDemandsForOneProduct.get(indexOfM);
                int month = indexOfM % 12;
                String label = "";
                switch (month) {
                    case 0:
                        label = Consts.JAN;
                        break;
                    case 1:
                        label = Consts.FEB;
                        break;
                    case 2:
                        label = Consts.MAR;
                        break;
                    case 3:
                        label = Consts.APR;
                        break;
                    case 4:
                        label = Consts.MAY;
                        break;
                    case 5:
                        label = Consts.JUN;
                        break;
                    case 6:
                        label = Consts.JUL;
                        break;
                    case 7:
                        label = Consts.AUG;
                        break;
                    case 8:
                        label = Consts.SEP;
                        break;
                    case 9:
                        label = Consts.OCT;
                        break;
                    case 10:
                        label = Consts.NOV;
                        break;
                    case 11:
                        label = Consts.DEC;
                        break;
                }
                int year = indexOfM / 12 + Consts.BASE_YEAR;
                label = label + " " + year;
                result.add(new LabelNValue(label, value));
            }
        } else {
            System.out.println("actual demands for one product is null");
            return null;
        }
        return result;
    }
}
